home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Applications / Graphics / nxyplot / Source / ColumnSelectionHandler.m < prev    next >
Text File  |  1992-07-20  |  12KB  |  365 lines

  1.  
  2. /* Generated by Interface Builder */
  3.  
  4. #import "ColumnSelectionHandler.h"
  5. #import "Plot.h"
  6. #import "defs.h"
  7. #import <appkit/Font.h>
  8. #import <appkit/Panel.h>
  9. #import <appkit/Window.h>
  10. #import <appkit/Matrix.h>
  11. #import <appkit/View.h>
  12. #import <appkit/ButtonCell.h>
  13. #import <dpsclient/wraps.h>
  14. #import <appkit/color.h>    /* only for "blanking out" parts of a matrix */
  15. #import <appkit/graphics.h>    /* ditto */
  16.  
  17. /*
  18.  * The job of this object is to keep the appearance of the Column Selection panel
  19.  * in accord with the state of the program.  We do not update the Column Selection
  20.  * panel every time a file is read in, since it is expected that this option will
  21.  * not be heavily used.
  22.  */
  23.  
  24. @implementation ColumnSelectionHandler
  25.  
  26. - init
  27. {
  28. /*
  29.  * This global variable keeps track of whether the column selection window
  30.  * has ever been displayed.  We can avoid updating after the selective
  31.  * file removal if we have never been displayed.
  32.  */ 
  33.   everVisible = NO;
  34.   return self;
  35. }
  36.  
  37.  
  38. /*
  39.  * Arrange to blank out the disabled buttons.  The "right" way to do this
  40.  * is probably to have a "RaggedMatrix" class which allows a different
  41.  * number of columns in each row, but there are too many other issues
  42.  * raised by that to deal with right now.  Note that having such a class
  43.  * would allow us to correctly deal with the problem of correctly
  44.  * redisplaying the matrix after a resize operation on the window.
  45.  * (We currently get around that problem by making ourself the window's delegate 
  46.  * and defining windowDidResize:, and in that method calling
  47.  * perform:with:afterDelay:cancelPrevious, but this is highly suboptimal.)
  48.  */
  49. - eraseDisabledCells:sender
  50. {
  51.   int n, j, numrows, numcols, ncurves;
  52.   NXRect r;
  53.  
  54.   [columnMatrix getNumRows:&numrows numCols:&numcols];
  55.   [columnMatrix lockFocus];
  56.   NXSetColor([columnMatrix backgroundColor]);
  57. /* The NXSetColor call has to come after the lockFocus; otherwise, when
  58.  * this method is called by fixPanel, the color always comes out black
  59.  * even if something else is specifically requested.  The weird part is,
  60.  * when this method is called by fixRow, the color is correct when the
  61.  * NXSetColor call is outside the lockFocus.
  62.  */
  63.   for (n=0; n<[plotParam nFiles]; n++) {
  64.     ncurves = [plotParam nCurves:n];
  65.     if (ncurves < numcols-1) {
  66.       for (j=ncurves; j<numcols; j++) {
  67.         [columnMatrix getCellFrame:&r at:n :j+1]; /* note the j+1 */
  68.         NXRectFill(&r);
  69.       }
  70.     }
  71.   }
  72.   [columnMatrix unlockFocus];
  73.   NXPing();
  74.   return self;
  75. }
  76.  
  77.  
  78. - removeAll:sender
  79. /* This method is called by the "remove all files" method of the Plot object. */
  80. {
  81.   int n, j;
  82.   int numrows, numcols;
  83.   NXSize cellsize, intercell;
  84.   NXCoord dy;
  85.  
  86.   /* Do something only if the window has ever been displayed  */
  87.   if (everVisible) {
  88.     [columnMatrix getNumRows:&numrows numCols:&numcols];
  89.     [columnMatrix getCellSize:&cellsize];
  90.     [columnMatrix getIntercell:&intercell];
  91.     /*
  92.      * Wipe out everything.
  93.      */
  94.     dy = (NXCoord)(numrows - 1) * (cellsize.height + intercell.height);
  95.     [columnMatrix moveBy:0.0 :dy];
  96.     /*
  97.      * Before doing renewRows, set the state of all the cells to 0; this is
  98.      * because the renewRows method just recycles the cells, and later on
  99.      * we may find ourselves using a cell which has state=1 when we don't
  100.      * want such a beast.  Also enable all cells (paranoia strikes).
  101.      */
  102.     for (n=0; n<numrows; n++) {
  103.       for (j=0; j<numcols; j++) {
  104.     [[columnMatrix cellAt:n :j] setState:0];
  105.     [[columnMatrix cellAt:n :j] setEnabled:YES];
  106.       }
  107.     }
  108.     [columnMatrix renewRows:1 cols:1];
  109.     [columnMatrix sizeToCells];
  110.     [[columnMatrix cellAt:0 :0] setEnabled:YES];
  111.     [[columnMatrix cellAt:0 :0] setType:NX_TOGGLE];
  112.     [[columnMatrix cellAt:0 :0] setState:1];
  113.     [filenameMatrix moveBy:0.0 :dy];
  114.     [filenameMatrix renewRows:1 cols:1];
  115.     [[filenameMatrix cellAt:0 :0] setStringValue:"filename"];
  116.     [filenameMatrix sizeToCells];
  117.     [columnText renewRows:1 cols:1];
  118.     [columnText sizeToCells];
  119.     /* Do some drawing now.  Display the view. */
  120.     [[columnMatrix window] display];
  121.     NXPing();            /* needed??? */
  122.   }
  123.   return self;
  124. }
  125.  
  126.  
  127. - fixPanel:sender
  128. /*
  129.  * The select column button activates this method; it is also called from
  130.  * windowDidResize, from Plot.m in postludeToReading, and by the update
  131.  * button on the panel.  We have to fix up the column selection panel
  132.  * so that it's correct.
  133.  */
  134. {
  135.   int n, j;
  136.   int nfilestotal = [plotParam nFiles], maxcols = 0, ncurves;
  137.   char title[80];
  138.   int numrows, numcols;
  139.   BOOL one_on;
  140.   NXSize cellsize, intercell;
  141.   NXCoord dy;
  142.   int * turned_on;
  143.  
  144.   if (everVisible == NO) everVisible = YES;
  145.  
  146.   [columnMatrix getNumRows:&numrows numCols:&numcols];
  147.   [columnMatrix getCellSize:&cellsize];
  148.   [columnMatrix getIntercell:&intercell];
  149.  
  150.   /*
  151.    * We have to create some additional rows and perhaps some additional columns.
  152.    */
  153.   // First figure out how many rows and columns the matrices should have
  154.   for (n=0; n<nfilestotal; n++) {
  155.     maxcols = MAX(maxcols, [plotParam nCurves:n]);
  156.   }
  157.   maxcols++;            /* this is the number of columns needed */
  158.   if (numrows != nfilestotal  ||  numcols != maxcols) {
  159.     /* The renewRows:cols: message might have the side effect of setting
  160.      * the state of all the cells of the matrix back to 0; this is undesired,
  161.      * so before changing the number of rows and/or columns in the matrix,
  162.      * make sure we remember which cells in each row were turned on.
  163.      */
  164.     turned_on = (int *)malloc(numrows * sizeof(int)); /* should do error check */
  165.     for (n=0; n<numrows; n++) {
  166.       turned_on[n] = 0;        /* cautious initialization */
  167.       for (j=0; j<numcols; j++) {
  168.     if ([[columnMatrix cellAt:n :j] state] == 1) {
  169.       turned_on[n] = j;
  170.       break;
  171.     }
  172.       }
  173.     }
  174.     [columnMatrix renewRows:nfilestotal cols:maxcols];
  175.     for (n=numrows; n<nfilestotal; n++) {
  176.       [[columnMatrix cellAt:n :0] setState:1];
  177.       for (j=1; j<maxcols; j++) {
  178.     [[columnMatrix cellAt:n :j] setState:0];
  179.       }
  180.     }      
  181.     /* And now turn cells back on. */
  182.     for (n=0; n<numrows; n++) {
  183.       for (j=0; j<numcols; j++) {
  184.     [[columnMatrix cellAt:n :j] setState:0];
  185.       }
  186.       [[columnMatrix cellAt:n :turned_on[n]] setState:1];
  187.     }
  188.     free((void *)turned_on);
  189.   }
  190.   [columnMatrix sizeToCells];
  191.   dy = (float)(nfilestotal - numrows) * (cellsize.height + intercell.height);
  192.   [columnMatrix moveBy:0.0 :-dy];
  193.   // Some of the cells may come in with type NULLCELL; fix them here
  194.   for (n=0; n<nfilestotal; n++) {
  195.     for (j=0; j<maxcols; j++) {
  196.       [[columnMatrix cellAt:n :j] setEnabled:YES];
  197.       [[columnMatrix cellAt:n :j] setType:NX_TOGGLE];
  198.     }
  199.   }
  200.   // Make sure exactly one button is turned on in each row
  201.   for (n=0; n<nfilestotal; n++) {
  202.     one_on = NO;
  203.     for (j=0; j<maxcols; j++) {
  204.       if ([[columnMatrix cellAt:n :j] state] == 1) {
  205.     one_on = YES;
  206.     break;
  207.       }
  208.     }
  209.     if (!one_on)
  210.       [[columnMatrix cellAt:n :0] setState:1];
  211.   }
  212.   // We surround the [columnMatrix display] and [self eraseDisabledCells]
  213.   // calls with the disableFlushWindow, reenableFlushWindow, and flushWindow
  214.   // calls to prevent the disabled matrix cells from being visible for a long
  215.   // time while they're drawn and then erased.
  216.   [columnPanel disableFlushWindow];
  217.   [columnMatrix display];
  218.   // Disable cells that shouldn't appear.
  219.   for (n=0; n<nfilestotal; n++) {
  220.     ncurves = [plotParam nCurves:n];
  221.     if (ncurves < maxcols-1) {
  222.       for (j=ncurves; j<maxcols; j++) {
  223.         [[columnMatrix cellAt:n :j+1] setType:NX_NULLCELL]; /* note the j+1 */
  224.         [[columnMatrix cellAt:n :j+1] setEnabled:NO];       /* again j+1    */
  225.       }
  226.     }
  227.   }
  228.  
  229.   // We have to put the makeKeyAndOrderFront before the eraseDisabledCells
  230.   // method, because eraseDisabledCells does a lockFocus and lockFocus needs
  231.   // a real window to draw into.  We put the makeKeyAndOrderFront here rather
  232.   // than at the beginning of this method because this way the disabled cells
  233.   // of the matrix are visible for a shorter period of time.
  234.   [columnPanel makeKeyAndOrderFront:self];
  235.  
  236.   // Now erase those disabled cells.
  237.   [self eraseDisabledCells:self];
  238.   [columnPanel reenableFlushWindow];
  239.   [columnPanel flushWindowIfNeeded];
  240.   NXPing();            /* needed? */
  241.  
  242.   // That finishes with the columnMatrix; now for the filename Matrix.
  243.   [filenameMatrix renewRows:nfilestotal cols:1];
  244.   for (n=0; n<nfilestotal; n++) {
  245.     if (!strncmp([plotParam filename:(unsigned)n], "pasteboard", 10))
  246.       sprintf(title, "pasteboard");
  247.     else
  248.       sprintf(title, strrchr([plotParam filename:(unsigned)n], '/') + 1);
  249.     [[filenameMatrix cellAt:n :0] setStringValue:title];
  250.   }
  251.   [filenameMatrix sizeToCells];
  252.   [filenameMatrix moveBy:0.0 :-dy];
  253.   [filenameMatrix display];
  254.  
  255.   // And now for the columnText matrix.
  256.   [columnText renewRows:1 cols:maxcols];
  257.   for (j=1; j<=maxcols; j++) {
  258.     sprintf(title, "%d", j);
  259.     [[columnText cellAt:0 :(j-1)] setStringValue:title];
  260.   }
  261.   [columnText sizeToCells];
  262.   [columnText display];
  263.  
  264.   return self;
  265. }
  266.  
  267.  
  268. - fixRow:sender
  269. /* The sender is columnMatrix in the column selection panel; we want to
  270.  * turn off some buttons in the matrix row.
  271.  */
  272. {
  273.   int row, col, i, prev_col=0, numrows, numcols;
  274.  
  275.   row = [sender selectedRow];
  276.   col = [sender selectedCol];
  277.   [sender getNumRows:&numrows numCols:&numcols];
  278.  
  279.   // Find out what column was previously highlighted:
  280.   for (i=0; i<numcols; i++) {
  281.     if ( [[sender cellAt:row :i] state] == 1  &&  i != col) {
  282.       prev_col = i;
  283.       break;
  284.     }
  285.   }
  286.   // adjust the matrix
  287.   for (i=0; i<numcols; i++) {
  288.     [ [sender cellAt:row :i] setState:0];
  289.   }
  290.   [ [sender cellAt:row :col] setState:1];
  291.  
  292.   // The disableFlushWindow, reenableFlushWindow, and flushWindow methods
  293.   // bracket the [sender display] and [self eraseDisabledCells] methods, with
  294.   // the result that the disabled cells are not visibly drawn on the screen.
  295.   // This is the way it should be.
  296.   [columnPanel disableFlushWindow];
  297.   [sender display];
  298.   [self eraseDisabledCells:self];
  299.   [columnPanel reenableFlushWindow];
  300.   [columnPanel flushWindowIfNeeded];
  301.  
  302.   // swap the pointers as requested
  303.   [plotParam swapColumns:prev_col :col  forFileNumber:row];
  304.   return self;
  305. }
  306.  
  307. /*
  308.  * We call fixPanel here, rather than eraseDisabledCells (which is more
  309.  * logical), because for some reason eraseDisableCells doesn't seem to work
  310.  * properly!  The method fixPanel: does a lot more work than is really
  311.  * needed.  Sigh... This should all be cleaned up.
  312.  */
  313. - windowDidResize:sender
  314. {
  315.   [self perform:@selector(fixPanel:)
  316.         with:self
  317.         afterDelay:1        /* wait 0.001 second */
  318.         cancelPrevious:YES];
  319.   return self;
  320. }
  321.  
  322.  
  323. /*
  324.  * This is called by the selective file removal code in Plot.m.
  325.  */
  326. - update:sender
  327. {
  328.   int n, nfilestotal = [plotParam nFiles], num_removed = 0;
  329.   NXSize cellsize, intercell;
  330.   NXCoord dy;
  331.  
  332.   /* Do something only if the window has ever been displayed  */
  333.   if (everVisible) {
  334.     [columnMatrix getCellSize:&cellsize];
  335.     [columnMatrix getIntercell:&intercell];
  336.     /*
  337.      * Count down the file removal panel, removing rows as needed.
  338.      */
  339.     for (n = nfilestotal-1; n>=0; n--) {
  340.       if ([[fileRemovalButtons cellAt:n :0] state] == 1) {
  341.     /* This file is to be removed. */
  342.     num_removed++;
  343.     [columnMatrix removeRowAt:n andFree:YES];
  344.     [filenameMatrix removeRowAt:n andFree:YES];
  345.       }
  346.     }
  347.     [columnMatrix sizeToCells];
  348.     [filenameMatrix sizeToCells];
  349.     if (num_removed > 0) {
  350.       dy = (NXCoord)(num_removed) * (cellsize.height + intercell.height);
  351.       [columnMatrix moveBy:0.0 :dy];
  352.       [filenameMatrix moveBy:0.0 :dy];
  353.     }
  354.     /* Do some drawing now.  Display the view. */
  355.     [[columnMatrix window] display];
  356.     NXPing();            /* needed??? */
  357.   }
  358.  
  359.   return self;
  360. }
  361.  
  362.  
  363.  
  364. @end
  365.